#ifndef _OM_BASE_H_
#define _OM_BASE_H_

#include <queue>

namespace OmPublic
{
	using std::deque;
	// limited length queue. Notice typename T must have correct copy constructor and operator '=' function
	// when push back to the queue, it will pop front the member if the member's count is grater or equal the length
	//		typename T. type
	//		size_t length. the length	
	template<typename T, size_t length>
	class LimitedLengthQueue
	{
	public:
		typedef bool (*SortFunc) (const T & t1, const T & t2); 

	public:
		// clear
		void clear()
		{
			mQueue.clear();
		}

		// sort
		void sort(SortFunc func)
		{
			std::sort(mQueue.begin(), mQueue.end(), func);
		}

		// erase items.
		// para
		//		size_t start. the start position
		//		size_t quantity. quantity, default is 1.
		bool erase(size_t start, size_t quantity = 1)
		{
			if (!isValidMember(start) || !isValidMember(start + quantity -1))
				return false;

 			for (size_t i = 0; i < quantity; ++i)
	 			mQueue.erase(mQueue.begin() + start);

			return true;
		}

		// push back, it will pop front the member if the member's count is grater or equal the length
		// para
		//		const T & t. the data to be pushed back
		void pushBack(const T & t)
		{
			while (mQueue.size() >= length)
				mQueue.pop_front();
			mQueue.push_back(t); // it means T must has correct copy constructor function
		}

		// if the member which the index referring is valid
		// para
		//		size_t index. the index
		// return true if is valid, else return false
		bool isValidMember(size_t index) const
		{
			return index < mQueue.size();
		}

		// get member const reference. 
		// before calling this function, must guarantee the member referring to the index is valid.
		// call isValidMember() to know if the member is valid.
		// para
		//		size_t index. the index
		// return const T&. the member's const reference.
		const T & getMemberConst(size_t index) const
		{
			return mQueue[index];
		}

		// get member reference
		// before calling this function, must guarantee the member referring to the index is valid.
		// call isValidMember() to know if the member is valid.
		// para
		//		size_t index. the index
		// return T&. the member's reference
		T & getMember(size_t index) 
		{
			return mQueue[index];
		}

		// set member. notice only valid member will be set.
		// para
		//		size_t index. the member index
		//		const T & t. the reference of the value.
		void setMember(size_t index, const T & t)
		{
			if (isValidMember(index))
			{
				mQueue[index] = t; // it means T must have the correct operator function '='
			}
		}

		// get member count
		// return member count.
		size_t getMemberCount() const {return mQueue.size();}

		// get queue length
		// return the length.
		static size_t getLength(){return length;}

	private:
		deque<T> mQueue;

	};

	template <typename T, size_t length>
	class LimitedLengthQueue2
	{
	public:
		LimitedLengthQueue2() {reset();}
		
		void reset()
		{
			mFront = mTail = 0;
		}
		
		void popFront(size_t count) 
		{
			if (getMemberCount() < count) // must check count is less than member count first
				return ;

			mFront = (mFront + count) % length;
		}

		template <typename T1>  // only for integer type (long, int, short) and only for T is signed char or unsigned char
		void getData(T1 & destination, size_t index, bool reverse = true) // must check i + sizeof(destination) less than member count first
		{
			size_t memberCount = getMemberCount();
			if (index + sizeof(T1) > memberCount)
				return ;

			unsigned char * d = (unsigned char*) &destination;
						
			if (reverse)
			{
				for (size_t i = 0; i < sizeof(T1); ++i)
				{
					d[i] = getMember(index + sizeof(T1) - 1 - i);
				}	
			}
			else
			{
				for (size_t i = 0; i < sizeof(T1); ++i)
				{
					d[i] = getMember(index + i);
				}
			}
		}

		void getData(vector<T> & v, size_t index, size_t count) 
		{
			if (index + count > getMemberCount()) // must check index + count less than or equal member count first
				return;
			
			for (size_t i = index; i < count; ++i)
			{
				v.push_back(getMember(i));
			}
		}

		const T & getMember(size_t i) // i is index, must check i less than  member count first
		{
			size_t pos = (mFront + i) % length ;
			return mData[pos];
		}

		void pushBack(const T & data) // must check has enough free space first by caller
		{		
			mData[mTail] = data;
			mTail = (mTail + 1) % length;
		}
		
		void pushBack(const T * data, size_t count) // must check has enough free space first by caller
		{			
			if (mTail + count <= length)
			{
				memcpy(mData + mTail, data, count);
				mTail += count;
			}
			else
			{
				size_t freeInTail = length - mTail;
				memcpy(mData + mTail, data, freeInTail);
				memcpy(mData, data + freeInTail, count - freeInTail);
				mTail = count - freeInTail;
			}
		}


		size_t getFreeSpace() const
		{
			if (mFront == mTail)
				return length;
			size_t i = (mFront <= mTail ? mFront + length : mFront) - mTail;
			return i;
		}

		bool isFull() const
		{
			return getFreeSpace() == 0;
		}		

		void erase(size_t start, size_t count) // must check count less than length first
		{
			
		}
	
		size_t getMemberCount() const
		{
			return (mTail >= mFront ? mTail : mTail + length) - mFront;
		}
		
		static size_t getLength() {return length;}
	private:
		T mData[length];
		size_t mFront, mTail;
	};
}

#endif